package com.bosssoft.trainee.service.imp;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bosssoft.trainee.common.exception.Asserts;
import com.bosssoft.trainee.dao.UserDao;
import com.bosssoft.trainee.mbg.dto.UserDTO;
import com.bosssoft.trainee.mbg.mapper.UserMapper;
import com.bosssoft.trainee.mbg.po.Resource;
import com.bosssoft.trainee.mbg.po.User;
import com.bosssoft.trainee.mbg.vo.UserVO;
import com.bosssoft.trainee.security.bo.UserBO;
import com.bosssoft.trainee.security.util.JwtTokenUtil;
import com.bosssoft.trainee.service.RoleService;
import com.bosssoft.trainee.service.UserCacheService;
import com.bosssoft.trainee.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author: wuxin
 * @Date: 2022/6/17
 * @Project rbac
 * @Version 1.0
 * @Description
 */
@Service
@Slf4j
public class UserServiceImp implements UserService {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserCacheService userCacheService;
    @Autowired
    private RoleService roleService;

    /**
     * 用户登录获取token
     *
     * @param username
     * @param password
     */
    @Override
    public String login(String username, String password) {
        String token = null;
        // 密码需要客户端加密后传递
        try {
            // 获得用户信息
            UserDetails userDetails = loadUserByUsername(username);
            // 判断用户状态
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                Asserts.fail("密码不正确");
            }
            if (!userDetails.isEnabled()) {
                Asserts.fail("帐号已被禁用");
            }
            // 生成 Token
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
            // 可以插入登录历史
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    /**
     * 根据用户名获取后台管理员
     *
     * @param username
     */
    @Override
    public UserVO getByUsername(String username) {
        // 从缓存中获取
        UserVO userVO = userCacheService.getUser(username);
        if (userVO != null) return userVO;
        User user = new User();
        user.setUsername(username);
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.lambda().eq(User::getUsername, username);
        //将User转为UserVo
        userVO = userToUserVo(userMapper.selectOne(userWrapper));
        return userVO;
    }

    /**
     * 获取用户信息
     *
     * @param username
     */
    @Override
    public UserBO loadUserByUsername(String username) {
        UserVO userVO = getByUsername(username);
        if (userVO != null) {
            userCacheService.setUser(userVO);
            List<Resource> resourceList = userVO.getResources();
            return new UserBO(userVO, resourceList);
        }
        throw new UsernameNotFoundException("用户名或密码错误");
    }

    /**
     * 通过token获取用户的详细信息
     *
     * @param token
     * @return
     */
    @Override
    public UserVO getUserInfo(String token) {
        return getByUsername(jwtTokenUtil.getUserNameFromToken(token));
    }

    /**
     * 刷新token的功能
     *
     * @param oldToken 旧的token
     */
    @Override
    public String refreshToken(String oldToken) {
        return jwtTokenUtil.refreshHeadToken(oldToken);
    }

    /**
     * 根据Id获取用户
     *
     * @param id
     */
    @Override
    public UserVO getById(int id) {
        return userToUserVo(userMapper.selectById(id));
    }

    /**
     * 根据example获取用户列表
     *
     * @param pageSize 页大小
     * @param pageNum  页数
     * @param example  样例
     * @return 和example中属性相同的用户列表
     */
    @Override
    public Page<User> getList(int pageSize, int pageNum, UserDTO example) {
        User user = new User();
        BeanUtil.copyProperties(example, user);
        QueryWrapper<User> userqw = new QueryWrapper<>(user);
        // Page<User> userPage = userMapper.selectPage(new Page<>(pageNum, pageSize), userqw);
        // Page<UserVO> userVOPage = new Page<>();
        // BeanUtil.copyProperties(userPage,userVOPage);
        // return userVOPage;
        return userMapper.selectPage(new Page<>(pageNum, pageSize), userqw);
    }

    /**
     * 新增用户
     *
     * @param userDTO 新增对象
     * @return 受影响的记录数
     */
    @Override
    public int addUser(UserDTO userDTO) {
        if (!checkUsername(userDTO.getUsername(),userDTO.getId())
                && !checkWorkerNum(userDTO.getWorkerNum(),userDTO.getId())) {
            User user = new User();
            BeanUtil.copyProperties(userDTO, user);
            user.setId(null);
            String encodePassword = passwordEncoder.encode(user.getPassword());
            user.setPassword(encodePassword);
            return userMapper.insert(user);
        } else {
            Asserts.fail("用户名或工号重复");
            return 0;
        }
    }

    /**
     * 根据Id删除用户
     *
     * @param id 删除对象id
     * @return 受影响的记录数
     */
    @Override
    public int deleteById(int id) {
        return userMapper.deleteById(id);
    }

    /**
     * 更新用户用户信息
     *
     * @param userDTO 更新对象
     * @return 受影响的记录数
     */
    @Override
    public int updateUser(UserDTO userDTO) {
        if (!checkUsername(userDTO.getUsername(),userDTO.getId())
                && !checkWorkerNum(userDTO.getWorkerNum(),userDTO.getId())) {
            User user = new User();
            BeanUtil.copyProperties(userDTO, user);
            //不更新密码
            // String encodePassword = passwordEncoder.encode(user.getPassword());
            // user.setPassword(encodePassword);
            userCacheService.delUser(user.getId());
            return userMapper.updateById(user);
        }else{
            Asserts.fail("用户名或工号重复");
            return 0;
        }
    }

    /**
     * 检查工号是否被使用
     *
     * @param workerNum 工号
     * @return true:被使用，false:未被使用
     */
    @Override
    public boolean checkWorkerNum(String workerNum,Integer id) {
        if(id==null){
            id = 0;
        }
        return userDao.checkWorkerNum(workerNum,id) > 0;
    }

    /**
     * 检查用户名是否被使用
     *
     * @param username 用户名
     * @return true:被使用，false:未被使用
     */
    @Override
    public boolean checkUsername(String username,Integer id) {
        if(id==null){
            id = 0;
        }
        return userDao.checkUsername(username,id) > 0;
    }

    /**
     * 用户登出
     *
     * @param token
     */
    @Override
    public void logout(String token) {
        // 从缓存中获取
        UserVO userVO = userCacheService.getUser(jwtTokenUtil.getUserNameFromToken(token));
        if (userVO != null){
            userCacheService.delUser(userVO.getId());
        }
    }

    /**
     * 将User转为UserVo
     * @param user
     * @return
     */
    private UserVO userToUserVo(User user){
        if(user==null){
            return null;
        }
        UserVO userVO =new UserVO();
        BeanUtil.copyProperties(user,userVO);
        userVO.setRoles(roleService.getRoleByIds(user.getRoleIds()));
        userVO.setResources(roleService.getResourceByRoleIds(user.getRoleIds()));
        return userVO;
    }
}
